
import com.service.AService;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

//模拟 循环依赖问题
//该问题和Spring Bean的生命周期有关


//AService:
//0. createSet集合用来记录哪些类正在创建还没有放入单例池中(还没有创建完)
//1. 实例化--->原始对象--->放入三级缓存中
//2.1 填充bService属性  ---> 去单例池中找bService 找到对应的对象-->如果没有找到就创建BService对应的Bean
//2.2 填充cService属性  ---> 去单例池中找cService 找到对应的对象-->如果没有找到就创建cService对应的Bean
//3. 填充其他属性
//4. 正常进行AOP--->会先判断AService有没有进行过AOP 注意 如果是正常进行AOP(没有循环依赖问题) 那么给BService注入的还是原始对象AService
//4.1 拿到一个代理对象 放入二级缓存
//5. 放入单例池中(一级缓存SingletonObjects):

//BService:
//1. 实例化--->原始对象-->放入二级缓存（earlySingletonObjects）
//2. 填充aService属性  ---> 去单例池中找aService 找到对应的对象-->没有或者对象正在创建中（createSet）
// -->二级缓存找原始对象或代理对象==->没有-->AService正在创建中出现了循环依赖（从createSet集合发现的）
//---> 从三级缓存中找一个lambda表达式 -->判断AService是否需要AOP 需要AOP执行表达式 不需要就不执行
// -->得到AService的代理对象或者得到原始对象  并把代理对象放入二级缓存中 并从三级缓存中移除（根据beanName移除） 这是为了确保单例一致性（同一个beanName只能有一个对象）
//3. 填充其他属性
//4. XXX
//5. 放入单例池中(一级缓存)

//cService:
//1. 实例化--->原始对象-->放入二级缓存（earlySingletonObjects）
//2. 填充aService属性  ---> 去单例池中找aService 找到对应的对象-->没有--》找二级缓存-》有-》将代理对象注入
//3. 填充其他属性
//4. XXX
//5. 放入单例池中(一级缓存)



//  第一级缓存：单例池:,Map<beanName---对象>（singletonObjects）
//  二级缓存：earlySingletonObjects
//  二级缓存可以初步解决循环依赖问题 但是 如果AService执行了AOP 那么单例池中放的就是AService的代理对象不是他的原始对象
//   而我们依赖注入需要将代理对象注入到BService的aService属性 但是此时注入的是二级缓存中的原始对象
//   我们可以提前进行AOP  在第一步就将AOP代理对象存入二级缓存
//   三级缓存singletonFactories  由于AOP创建出来的代理对象需要原始对象  所以我们需要将一个三级缓存
//   但是三级缓存并没有存入原始对象而是存入的是一个lambda表达式 该表达式执行会得到beanName beanDefinition和原始对象
//   该表达式存入后不会立即执行  而是判断是否需要AOP 在BService 第二步中出现了循环依赖并且AService需要AOP 那么才执行这个表达式

// 细节： 一级缓存是concurrentHashMap
//       二级缓存和三级缓存都是普通的HashMap




public class Test {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
        AService aService = (AService) applicationContext.getBean("aService");
        aService.test();

    }
}
